﻿using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.ComponentModel;
using System.Linq;
using AutoMapper;
using RemoteTestRunner.BusinessLogic.Views;
using RemoteTestRunner.Contracts;
using ICommand = System.Windows.Input.ICommand;

namespace RemoteTestRunner.BusinessLogic.ViewModels
{
    public class ProjectAdminViewModel : INotifyPropertyChanged
    {
        // private DataSet _testData;
        // private readonly IAdminView _view;
        // private IWpfDialogWindow wpfDialogWindow;

        public ProjectAdminViewModel()
        {
            PropertyChanged += ProjectAdminViewModel_PropertyChanged;

            // TODO: Add can executes
            AddProjectCommand = new RelayCommand(AddProjectCommandExecute);
            AddTestCommand = new RelayCommand(AddTestCommandExecute);
            DeleteProjectCommand = new RelayCommand(DeleteProjectCommandExecute);
            DeleteTestCommand = new RelayCommand(DeleteTestCommandExecute);
            CancelCommand = new RelayCommand(x => _wpfDialogWindow.CloseDialog(false));
            SaveCommand = new RelayCommand(SaveCommandExecute);

            Projects = new ObservableCollection<ProjectViewModel>();
            Tests = new ObservableCollection<Test>();

            Mapper.CreateMap<Project, ProjectViewModel>();
            Mapper.CreateMap<Test, TestViewModel>();
            Mapper.CreateMap<ProjectViewModel, Project>();
            Mapper.CreateMap<TestViewModel, Test>();

            var projects = IoC.Container.Resolve<IRtrService>().GetProjects();

            MapProjectDtoToViewModel(projects);
        }

        public ObservableCollection<ProjectViewModel> Projects { get; set; }

        #region Commands

        public ICommand AddProjectCommand { get; set; }
        public ICommand AddTestCommand { get; set; }
        public ICommand DeleteProjectCommand { get; set; }
        public ICommand DeleteTestCommand { get; set; }
        public ICommand CancelCommand { get; set; }
        public ICommand SaveCommand { get; set; }

        /// <summary>
        /// Adds a new project.
        /// </summary>
        /// <param name="obj">The obj.</param>
        private void AddProjectCommandExecute(object obj)
        {
            // Get next available ID...
            var nextProjectId = Projects.Count == 0 ? 1 : Projects.Select(x => x.Id).Max() + 1;
            var nextTestId = Tests.Count == 0 ? 1 : Tests.Select(x => x.Id).Max() + 1;

            var newProject = new ProjectViewModel { Name = "New Project", Id = nextProjectId };
            var newTest = new TestViewModel { Name = "New Test", Id = nextTestId };

            newProject.Tests.Add(newTest);
            Projects.Add(newProject);
            SelectedTest = newTest;
        }

        /// <summary>
        /// Adds a new test.
        /// </summary>
        /// <param name="viewModel">The view model.</param>
        private void AddTestCommandExecute(object viewModel)
        {
            // Get next available ID...
            var nextTestId = SelectedProject.Tests.Count == 0 ? 1 : SelectedProject.Tests.Select(x => x.Id).Max() + 1;

            SelectedProject.Tests.Add(new TestViewModel { Name = "New Test", Id = nextTestId });

            OnPropertyChanged("Projects");
        }

        /// <summary>
        /// Saves the current project/test settings.
        /// </summary>
        /// <param name="viewModel">The view model.</param>
        private void SaveCommandExecute(object viewModel)
        {
            var projects = new List<Project>();

            foreach (var project in Projects)
            {
                var mappedProject = Mapper.Map<ProjectViewModel, Project>(project);
                projects.Add(mappedProject);
            }

            IoC.Container.Resolve<IRtrService>().SaveProjects(projects);

            _wpfDialogWindow.CloseDialog(true);
        }

        /// <summary>
        /// Deletes the currently selected project.
        /// </summary>
        /// <param name="viewModel">The view model.</param>
        private void DeleteProjectCommandExecute(object viewModel)
        {
            if (SelectedProject != null)
            {
                Projects.Remove(SelectedProject);
            }
        }

        /// <summary>
        /// Deletes the currently selected test.
        /// </summary>
        /// <param name="viewModel">The view model.</param>
        private void DeleteTestCommandExecute(object viewModel)
        {
            if (SelectedProject != null && SelectedTest != null)
            {
                SelectedProject.Tests.Remove(SelectedTest);
            }
        }

        #endregion

        #region SelectedPath (INotifyPropertyChanged Property)

        private string _selectedPath;

        public string SelectedPath
        {
            get { return _selectedPath; }
            set
            {
                if (_selectedPath != value)
                {
                    _selectedPath = value;
                    OnPropertyChanged("SelectedPath");
                }
            }
        }

        #endregion

        #region SelectedTest (INotifyPropertyChanged Property)

        private TestViewModel _selectedTest;

        public TestViewModel SelectedTest
        {
            get { return _selectedTest; }
            set
            {
                if (_selectedTest != value)
                {
                    _selectedTest = value;
                    OnPropertyChanged("SelectedTest");
                }
            }
        }

        #endregion

        #region SelectedProject (INotifyPropertyChanged Property)

        private ProjectViewModel _selectedProject;

        public ProjectViewModel SelectedProject
        {
            get { return _selectedProject; }
            set
            {
                if (_selectedProject != value)
                {
                    _selectedProject = value;
                    OnPropertyChanged("SelectedProject");
                }
            }
        }

        #endregion

        #region Tests (INotifyPropertyChanged Property)

        private ObservableCollection<Test> _tests;

        public ObservableCollection<Test> Tests
        {
            get { return _tests; }
            set
            {
                if (_tests != value)
                {
                    _tests = value;
                    OnPropertyChanged("Tests");
                }
            }
        }

        #endregion

        #region IViewModelBase Members

        private IWpfDialogWindow _wpfDialogWindow;

        public void Start(IWpfDialogWindow wpfDialogWindow)
        {
            _wpfDialogWindow = wpfDialogWindow;
        }

        #endregion

        #region INotifyPropertyChanged values

        public event PropertyChangedEventHandler PropertyChanged;

        protected void OnPropertyChanged(string propertyName)
        {
            if (PropertyChanged != null)
            {
                PropertyChanged(this, new PropertyChangedEventArgs(propertyName));

                switch (propertyName)
                {
                    case "SelectedPath":
                        break;
                    default:
                        break;
                }
            }
        }

        #endregion

        private void ProjectAdminViewModel_PropertyChanged(object sender, PropertyChangedEventArgs e)
        {
            switch (e.PropertyName)
            {
                case "SelectedTest":
                    SelectedProject = GetParentProject(SelectedTest);

                    break;

                case "SelectedProject":
                    if (SelectedTest == null)
                    {
                        if (SelectedProject.Tests.Count == 0)
                        {
                            var newTest = new TestViewModel { Name = "New Test" };

                            SelectedProject.Tests.Add(newTest);
                        }

                        SelectedTest = SelectedProject.Tests[0];
                    }
                    else
                    {
                        var testParentProject = GetParentProject(SelectedTest);

                        if (testParentProject != null && !testParentProject.Equals(SelectedTest))
                        {
                            if (SelectedProject.Tests.Count == 0)
                            {
                                var newTest = new TestViewModel { Name = "New Test" };
                                SelectedProject.Tests.Add(newTest);
                            }
                            SelectedTest = SelectedProject.Tests[0];
                        }
                    }

                    break;
            }
        }

        private ProjectViewModel GetParentProject(TestViewModel test)
        {
            var projects = from project in Projects
                           from projectTest in project.Tests
                           where projectTest.Equals(test)
                           select project;

            return projects.FirstOrDefault();
        }

        private void MapProjectDtoToViewModel(IEnumerable<Project> projects)
        {
            Projects.Clear();

            foreach (var project in projects)
            {
                var mappedProject = Mapper.Map<Project, ProjectViewModel>(project);

                Projects.Add(mappedProject);
            }
        }
    }
}
